package com.cctc.juc.demo.Bitc.BwaitAndnotify.Bsynchronized;

import java.util.ArrayList;
import java.util.List;

/**
 * 临界区，共享资源。
 * - 使用前申请，使用后释放。
 */
public class Resource {
    private List<Object> resources = new ArrayList<>();

    /**
     * 线程间通信方式之：基于线程等待与唤醒机制。
     * - Object.wait() 方法：当线程执行的条件不满足时，释放自身持有的互斥锁，将当前线程放入到互斥锁的的等待队列内进行等待；
     * - Object.notify() 方法：当线程执行的条件满足时，从互斥锁的等待队列中 [随机取出一个] 线程，重新抢锁执行。
     * - Object.notifyAll() 方法：当线程执行的条件满足时，从互斥锁的等待队列中 [取出所有] 线程，重新抢锁执行。
     * 提示：实际应用中，如果没有特殊要求，应尽量使用 Object.notifyAll() 方法，因为 Object.notify() 方法是有风险的，可能导致某些等待线程永久不会被通知到。
     * 说明：以上方法调用的前提是均已获取到了 synchronized(互斥锁)，则这些方法必须是在 synchronized 方法或代码块中调用的，且使用的互斥锁必须是 synchronized(互斥锁) 中的互斥锁，否则将会抛出 IllegalMonitorStateException 异常。
     */

    private Object LOCK = new Object();

    public void apply(Object source, Object target) {
        synchronized (LOCK) {
            while (resources.contains(source) || resources.contains(target)) {
                try {
                    /**
                     * Object.wait() 方法
                     * - 当线程执行的条件不满足时，释放自身持有的互斥锁，将当前线程放入到互斥锁的的等待队列内进行等待。
                     */
                    LOCK.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            resources.add(source);
            resources.add(target);
        }
    }

    public void release(Object source, Object target) {
        synchronized (LOCK) {
            resources.remove(source);
            resources.remove(target);
            /**
             * Object.notify[All]() 方法
             * - 当线程执行的条件满足时，从互斥锁的等待队列中 [取出所有] 线程，重新抢锁执行。
             */
            LOCK.notifyAll();
        }
    }
}
